﻿/**
*    @file:    progressdaemonthread.cpp
*    @brief:
*    @author:  sanshi522@163.com
*    @date:    2025-01-05  01:02
*/
#include "progressdaemonthread.h"
#include <QCoreApplication>
#include <QDebug>
#include <QFileInfo>
#include <QProcess>
#include <QSettings>
#include <QTimer>
#include <progress.h>

ProgressDaemonThread::ProgressDaemonThread(QObject *parent)
    : QThread(parent)
{
    moveToThread(this);
    isRun = false;
    initParam();
    openInitStartProgress();
}

ProgressDaemonThread::~ProgressDaemonThread()
{
    qDebug() << __FUNCTION__;
    stop();
    quit();
    wait();
}

void ProgressDaemonThread::stop()
{
    isRun = false;
}

void ProgressDaemonThread::initParam()
{
    QSettings settings(QCoreApplication::applicationDirPath() + "/" + "config/service.ini", QSettings::IniFormat);
    settings.setIniCodec("UTF-8");

    open_sleep = settings.value("workParam/open_sleep", 1).toInt();
    settings.setValue("workParam/open_sleep", open_sleep);
}

void waitTimeout(uint64_t waitTime, bool &runFlag)
{
    for (int sleep_time = waitTime / 10; sleep_time > 0 && runFlag; sleep_time--)
    {
        QThread::msleep(10);
    }
}

void ProgressDaemonThread::slot_daemonDipose()
{
    QList<ProgressInfo> list = getProgressInfoList();
    for (ProgressInfo progressInfo : list)
    {
        Progress progress = progressInfo.getProgress();
        if (!isRun)
            break;
        QString exePath = progress.getPath();
        string progressPath = exePath.toStdString();

        if (!progress.getDaemon_open())
            continue;
        if (!QFileInfo::exists(exePath))
            continue; //路径错误
        //=====================================多开清理
        //如果该进程出现多个，只保留1个，其他的杀掉
        closeMultiOpenProcess(progressPath);
        DWORD progressId;
        if (ProgressManage::getProcessIdByPath(progressPath, progressId))
        {
            if (progress.getCpu_use_up() && progressInfo.getCpuUsageList().size() >= 5)
            {
                QList<float> cpuUseList = progressInfo.getCpuUsageList();
                float maxCpuUse = *max_element(cpuUseList.begin(), cpuUseList.end());
                if (maxCpuUse < progress.getCpu_level() && isRun)
                {
                    qDebug() << QString("CPU占用率：%1，重启程序%2 id:%3").arg(maxCpuUse).arg(progress.getName()).arg(progressId);
                    ProgressManage::killProcessById(progressId);                                                 //========杀死进程
                    waitTimeout(500, isRun);                                                                     //========杀死进程后等待
                    bool startState = startProgress(progressPath);                                               //========启动进程
                    writeLog(PROGRESS_START_CPUUSE, startState, progress.getName(), progress.getPath());         //========记录日志
                    waitTimeout((progress.getStart_sleep() <= 1 ? 1 : progress.getStart_sleep()) * 1000, isRun); //程序启动后等待时长
                }
            }
            if (progress.getHeartbeat_up())
            {
                int checkSucceed = -1;
                for (int count = 3; count > 0 && isRun && checkSucceed == -1; count--)
                {
                    checkSucceed = heartbeatManage.checkHeartbeat(QString(progress.getHeartbeat_msg()).toStdString(), progress.getHeartbeat_timeout_second());
                    waitTimeout(1000, isRun);
                }
                if (checkSucceed == -1 && isRun)
                { //校验失败且不退出
                    //qDebug() << QString("心跳校验失败！重启程序");
                    if (ProgressManage::getProcessIdByPath(progressPath, progressId))
                    {
                        ProgressManage::killProcessById(progressId);
                        for (int sleep_time = 50; sleep_time > 0 && isRun; sleep_time--)
                        {
                            QThread::msleep(10);
                        }
                    }
                    bool startState = startProgress(progressPath);                                               //========启动进程
                    writeLog(PROGRESS_START_HEARTBEAT, startState, progress.getName(), progress.getPath());      //========记录日志
                    waitTimeout((progress.getStart_sleep() <= 1 ? 1 : progress.getStart_sleep()) * 1000, isRun); //程序启动后等待时长
                }
            }
        }
        else
        {
            if (progress.getVanish_up())
            {                                                                                                //----------------消失启动策略
                bool startState = startProgress(progressPath);                                               //========启动进程
                writeLog(PROGRESS_START_VANISH, startState, progress.getName(), progress.getPath());         //========记录日志
                waitTimeout((progress.getStart_sleep() <= 1 ? 1 : progress.getStart_sleep()) * 1000, isRun); //程序启动后等待时长
            }
        }
    }
}

void ProgressDaemonThread::slot_progressInfoList(QList<ProgressInfo> list)
{
    setProgressInfoList(list);
}

void ProgressDaemonThread::openInitStartProgress()
{
    //------------------首次启动拉起
    ProgressService progressService;
    QList<Progress> progressList;
    if (!progressService.getList(progressList))
    {
        for (int sleep_time = 500; sleep_time > 0 && isRun; sleep_time--)
        {
            QThread::msleep(1);
        }
        qCritical() << "获取进程列表失败！";
        return;
    }

    for (int i = 0; i < progressList.size() && isRun; i++)
    {
        Progress progress = progressList.at(i);
        if (progress.getDaemon_open() && progress.getInit_start())
        {
            if (!QFileInfo::exists(QString(progress.getPath())))
            {
                qDebug() << "路径错误";
                continue; //路径错误
            }
            QString exePath = progress.getPath();
            string progressPath = exePath.toStdString();
            DWORD progressId;
            //如果查不到该进程则启动
            if (!ProgressManage::getProcessIdByPath(progressPath, progressId) && isRun)
            {
                bool startState = startProgress(progressPath);                                               //========启动进程
                writeLog(PROGRESS_START_INIT, startState, progress.getName(), progress.getPath());           //========记录日志
                waitTimeout((progress.getStart_sleep() <= 1 ? 1 : progress.getStart_sleep()) * 1000, isRun); //程序启动后等待时长
            }
        }
    }
}

void ProgressDaemonThread::closeMultiOpenProcess(string &progressPath)
{
    list<DWORD> pIds = ProgressManage::getProcessIdsByPath(progressPath);
    if (pIds.size() > 1)
    {
        qInfo() << __FUNCTION__ << QString("[%1]出现多个重复进程(%2个),执行清理！").arg(progressPath.c_str()).arg(pIds.size());
        bool isFrist = true;
        for (list<DWORD>::iterator it = pIds.begin()++; it != pIds.end(); it++)
        {
            if (isFrist)
            {
                isFrist = false;
                continue;
            }
            ProgressManage::killProcessById(*it);
        }
        pIds = ProgressManage::getProcessIdsByPath(progressPath);
        qInfo() << __FUNCTION__ << QString("清理后剩余%1个！").arg(pIds.size());
    }
}

bool ProgressDaemonThread::startProgress(string &progressPath)
{
    return ProgressManage::startProcessByPath_A(progressPath);
}

void ProgressDaemonThread::writeLog(int start_type, bool startState, QString progress_name, QString progress_path)
{
    QString startMsg = "";
    switch (start_type)
    {
    case PROGRESS_START_INIT:
        startMsg = "首启守护唤醒";
        break;
    case PROGRESS_START_VANISH:
        startMsg = "常在守护唤醒";
        break;
    case PROGRESS_START_CPUUSE:
        startMsg = "CPU守护唤醒";
        break;
    case PROGRESS_START_HEARTBEAT:
        startMsg = "心跳守护唤醒";
        break;
    case PROGRESS_START_USER:
        startMsg = "用户手动唤醒";
        break;
    default:
        startMsg = "未知模式唤醒";
        break;
    }
    if (startState)
    {
        startMsg = startMsg + "成功!";
    }
    else
    {
        startMsg = startMsg + "失败!";
    }

    DaemonLog daemonLog(0, QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"), startState ? start_type : PROGRESS_START_ERROR, progress_name, progress_path, startMsg);
    daemonLogService.saveOne(daemonLog);
}

void ProgressDaemonThread::setProgressInfoList(const QList<ProgressInfo> &value)
{
    QMutexLocker locker(&progressInfoListMutex);
    progressInfoList = value;
}

QList<ProgressInfo> ProgressDaemonThread::getProgressInfoList()
{
    QMutexLocker locker(&progressInfoListMutex);
    return progressInfoList;
}

void ProgressDaemonThread::run()
{
    signal_runStatus(true);
    isRun = true;
    waitTimeout(open_sleep, isRun); //启动延时等待
    QTimer daemonTimer;
    connect(&daemonTimer, &QTimer::timeout, this, &ProgressDaemonThread::slot_daemonDipose);
    daemonTimer.start(1000);
    exec();
    daemonTimer.stop();
    signal_runStatus(false);
}
